/***************************************************************************
 创建者: 华磊
 开始时间: 2018.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2017.5.8 类的具体实现代码编写

 ***************************************************************************/
#include "getsysinfo.h"

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>

#include <assert.h>
#include <regex.h>


static int readline( FILE *fp, int line_num, char* buf, int buf_size  )
{
    if(fp==NULL)
    {
        puts("The fd is null !");
        return 0;
    }
    if(feof(fp))
    {
        puts("The end of the file!");
        return 0;
    }
    int linecount=0;
    while ((fgets (buf, buf_size , fp)) != NULL)
    {
        if( line_num == linecount )
           break;
        ++linecount;//fputs (buf, stdout);
    }
    return linecount;
}


/*从字符串的左边截取n个字符*/
static char * left(char *dst,char *src, int n)
{
    char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(n>len)
        n = len;
    /*p += (len-n);*/   /*从右边第n个字符开始*/
    while(n--) *(q++) = *(p++);
    *(q++)='\0';
    return dst;
}

/*从字符串的中间m，截取n个字符*/
static char * strmid(char *dst,const char *src,  int m, int n=0)
{
    const char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(n>len || n==0)
        n = len-m;    /*从第m个到最后*/
    if(m<0)
        m=0;    /*从第一个开始*/
    if(m>len)
        return NULL;
    p += m;
    while(n--) *(q++) = *(p++);
    *(q++)='\0';
    return dst;
}

/*从字符串的右边截取n个字符*/
static char * strright(char *dst,char *src, int n)
{
    char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(n>len)
        n = len;
    p += (len-n);   /*从右边第n个字符开始*/
    while(*(q++) = *(p++));
    return dst;
}

static int reg_test( const char *string, const char *pattern ,char* buf, int buf_size )
{
    regex_t reg;
    regmatch_t pmatch[5];

    //memset(buf,'\0',buf_size);
    int ret = regcomp(&reg, pattern, REG_EXTENDED|REG_NEWLINE);  // 编译正则表达式，为reg分配内存
    assert( ret==0 );
    ret = regexec(&reg, string, 5, pmatch, 0);  // 匹配正则表达式
    if(ret == 0)
    {
        // 提取组信息,i从1开始,跳过整句
        for(int i=1;i<5&&pmatch[i].rm_so!=-1;i++)
        {
            int len = pmatch[i].rm_eo - pmatch[i].rm_so;  // 匹配长度
            {
               //  printf("len:%d",buf_size );
                if( buf_size >len ){
                    strncpy(buf, string+pmatch[i].rm_so, len);
                    buf[len]='\0';
                }
              //  printf("len:%d, buf:%s\n",len, buf);  // 显示kettas
            }
        }
        return 0;
    }else if(ret == REG_NOMATCH){
        printf("No match\n");
        return -1;
    }else{
        char err[100];
        regerror(ret,&reg,err,100); // 打印错误
        printf("error:%s\n",err);
        return -1;
    }

    regfree(&reg);  // 释放内存，重复使用regcomp()时，一定要调用regfree()，防止内存漏洞
}

static int get_usb_serial( const char *dev, char* serial) {
    ssize_t len;
    int i;
    char buf[256], *p;
    char buf2[256];
    char ndev[256];
    char pdev[256];
    len = strlen( dev );

   strmid( pdev, dev, 5 );// "/dev/"
  // printf("buf======%s===%s\n", pdev, dev);
   sprintf(ndev, "/sys/block/%s", pdev);
   if((access( ndev ,F_OK))==-1)
   {
       printf("%s not exis!\n",ndev );
       return -1;
   }
   len = readlink(ndev, buf, 256);//返回软链接所指向的文件。可能返回绝对或相对路径

    buf[len] = 0;
    sprintf(buf2, "/sys/block/%s", buf);// /sys/block//../
   // printf("buf5======%s===%s\n",buf2, ndev);

    if((access( buf2 ,F_OK))==-1){
        printf("file not exis!\n" );
        return -1;
    }
    for (i=0; i<6; i++) { //去掉6个
        p = strrchr(buf2, '/');//查找字符在指定字符串中从左面开始的最后一次出现的位置
        *p = 0;
    }
    strcat(buf2, "/serial");

    int f = open(buf2, 0);
    len = read(f, buf, 256);
    close(f);
    if (len <= 0) {
       // printf( "%s" );
        perror("read()");
        return -1;
    }
    buf[len-1] = 0;
    sprintf(serial ,"%s", buf);
    return 0;
}

static int get_current_dev( char *dev,int buf_size ){
    FILE *fp;
    char linedata[100];
    fp = fopen ("/etc/mtab", "r");
    if (fp == NULL)
    {
        fprintf (stderr, "No /etc/mtab file.\n");
        return -1;
    }
    readline(fp, 0, linedata,  100 );
    fclose (fp);
    char*devstr = strtok( linedata, " " );

    char *pattern = "\s*(/dev/[a-z]+)[0-9]+\s*";
    int ret= reg_test( devstr, pattern, dev , buf_size) ;
    if( 0!=ret || strlen(dev)<4 ){
        printf("get dev error: %s\n", dev);
        return -1;
    }
  //  printf("devstr=%s, %s\n",devstr, devbuf);
    return 0;
}

static int get_disk_serial (char*dev, char *id_buf )
{
    int fd;
    struct hd_driveid hid;
     fd = open( dev, O_RDONLY);//need to do hualei error
    if (fd < 0)
    {
        fprintf (stderr, "open hard disk device failed.\n");
        return -1;
    }
    //set_fs( KERNEL_DS );
  //  if (ioctl (fd, BLKGETSIZE, &hid) < 0)
    if (ioctl (fd, HDIO_GET_IDENTITY, &hid) < 0)
    {
        fprintf (stderr, "ioctl error.\n");
        return -1;
    }
    close (fd);


    int i;
#if 1
    int start_len=-1;
    int end_len=-1;

    int len=strlen((const char*)hid.serial_no );
    snprintf (id_buf, len  , "%s", hid.serial_no);
    for(i=0;i<len;i++){
        end_len=i;
        if( !isspace( hid.serial_no[i] ) ){
            if( start_len<0 ){
                start_len=i;
            }
            end_len=i+1;
        }else if( start_len>=0 ){
            break;
        }
    }
    if( start_len>-1 && end_len>-1 ){
       // printf ( "disk serial: xxxxxxxxxxxx %d, %d , %s\n", start_len, end_len, hid.serial_no );
        strmid( id_buf, (const char*)hid.serial_no, start_len, end_len-start_len );
    }else{
         printf ( "error: disk seria null !" );
        return -1;
    }
#else
    int len=strlen((const char*)hid.serial_no );
    snprintf (id_buf, len  , "%s", hid.serial_no);
    for(i=0;i<len;i++){
       if( !isspace( hid.serial_no[i] ) ){
                break;
       }
    }
    strmid( id_buf, (const char*)hid.serial_no, i );
#endif
   // printf ( "disk serial: %s\n", id_buf);
    return 0;
}

int getdiskid( char *buf )
{

    int ret=1;
    char dev[256];
    ret = get_current_dev( dev, 256 );//agv pc can not acquire current disk
    if( ret == 0 )
    {
        if( ret=get_disk_serial( dev, buf) ==0 ){
            printf("disk:%d, serial: %s\n", ret, buf);
            return 0;
        }else if( ret=get_usb_serial( dev, buf ) == 0){
            printf("usb flash: %d, serial: %s\n", ret, buf);
            return 0;
        }else{
            printf("vm: %d, serial: %s\n", ret, buf);
            return 0;
        }
    }
    return 1;
}

int getdiskid_method2 (char *id)
{
  size_t max=256;
  int fd;
  struct hd_driveid hid;
  FILE *fp;
  char line[0x100], *disk, *root, *p;

  fp = fopen ("/etc/mtab", "r");
  if (fp == NULL)
    {
      fprintf (stderr, "No /etc/mtab file./n");
      return -1;
    }

  fd = -1;
  while (fgets (line, sizeof line, fp) != NULL)
    {
      disk = strtok (line, " ");
      if (disk == NULL)
    {
      continue;
    }

      root = strtok (NULL, " ");
      if (root == NULL)
    {
      continue;
    }

      if (strcmp (root, "/") == 0)
    {
      for (p = disk + strlen (disk) - 1; isdigit (*p); p --)
            {
             *p = '/0';
            }
      fd = open (disk, O_RDONLY);
      break;
    }
    }

  fclose (fp);

  if (fd < 0)
    {
      fprintf (stderr, "open hard disk device failed./n");
      return -1;
    }

  if (ioctl (fd, HDIO_GET_IDENTITY, &hid) < 0)
    {
      fprintf (stderr, "ioctl error./n");
      return -1;
    }

  close (fd);

  snprintf (id, max, "%s", hid.serial_no);
  fprintf (stdout, "get hard disk serial number: %s/n", id);
  return 0;
}

static int example()
{
    printf("This is an example !\n");

    char  serial[256];
    getdiskid( serial );
    getdiskid_method2( serial );

#if 0
    char* str=" /dev/sdb123 ";
    char *pattern = "\s*(/dev/[a-z]+)[0-9]+\s*";
    char ret[200];
    reg_test( str, pattern, ret , 200);
    printf("xzxxxid : %s\n", ret);
#endif

    return 0;
}



#if 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>

static int init_hotplug_sock(void)
{
    struct sockaddr_nl snl;
    const int buffersize = 16 * 1024 * 1024;
    int retval;

    memset(&snl, 0x00, sizeof(struct sockaddr_nl));
    snl.nl_family = AF_NETLINK;
    snl.nl_pid = getpid();
    snl.nl_groups = 1;

    int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (hotplug_sock == -1) {
        printf("error getting socket: %s", strerror(errno));
        return -1;
    }

    /* set receive buffersize */
    setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));

    retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
    if (retval < 0) {
        printf("bind failed: %s", strerror(errno));
        close(hotplug_sock);
        hotplug_sock = -1;
        return -1;
    }

    return hotplug_sock;
}
#endif


#ifndef MAX_IFINDEX
# define MAX_IFINDEX    8
#endif

//int getmacaddr (const char *ip, char *id, size_t max)
//{

//  int i, sockfd;
//  struct sockaddr_in *loc;
//  struct ifreq req[1];

//  sockfd = socket (AF_INET, SOCK_DGRAM, 0);
//  if (sockfd < 0)
//    {
//      fprintf (stderr, "Unable to create socket./n");
//      return -1;
//    }

//  for (i = 0; i <= MAX_IFINDEX; ++ i)
//    {
//      req->ifr_ifindex = i;

//      if (ioctl (sockfd, SIOCGIFNAME, req) < 0)
//        {
//          fprintf (stderr, "ioctl error: %s/n", strerror (errno));
//          continue;
//        }

//      if (ioctl (sockfd, SIOCGIFADDR, req) < 0)
//        {
//          fprintf (stderr, "ioctl interface index [%d] error: %s/n", i, strerror (errno));
//          continue;
//        }

//      loc = (struct sockaddr_in *) (&(req->ifr_ifru.ifru_addr));
//      if (loc->sin_addr.s_addr == inet_addr (ip))
//        {
//          fprintf (stderr, "%s bind at %s./n", ip, req->ifr_name);
//          break;
//        }
//    }

//  if (i > MAX_IFINDEX)
//    {
//      fprintf (stderr, "input IP error./n");
//      close (sockfd);
//      return -1;
//    }

//  if (ioctl (sockfd, SIOCGIFHWADDR, req) < 0)
//    {
//      fprintf (stderr, "ioctl error: %s/n", strerror (errno));
//      close (sockfd);
//      return -1;
//    }

//  close (sockfd);

//  snprintf (id, max, "%02X%02X%02X%02X%02X%02X",
//            req->ifr_hwaddr.sa_data[0] & 0xff,
//            req->ifr_hwaddr.sa_data[1] & 0xff,
//            req->ifr_hwaddr.sa_data[2] & 0xff,
//            req->ifr_hwaddr.sa_data[3] & 0xff,
//            req->ifr_hwaddr.sa_data[4] & 0xff,
//            req->ifr_hwaddr.sa_data[5] & 0xff);

//  fprintf (stdout, "MAC address of %s: [%s]./n", req->ifr_name, id);
//  return 0;
//}


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <errno.h>

//#define ETH_NAME	"eth0"
//#define ETH_NAME	"enp1s0"

int getmacaddr_method2 (char *macOut,char *ethName)
{
    int sock;
    struct sockaddr_in sin;
    struct sockaddr sa;
    struct ifreq ifr;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1)
    {
    perror("socket");
    return -1;
    }

    strncpy(ifr.ifr_name, ethName, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;

    if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
    {
    perror("ioctl");
    return -1;
    }

    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    fprintf(stdout, "%s ip: %s\n", ethName, inet_ntoa(sin.sin_addr));

    memset(macOut, 0, sizeof(macOut));
    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
    {
    perror("ioctl");
    return -1;
    }

    memcpy(&sa, &ifr.ifr_addr, sizeof(sin));
    memcpy(macOut, sa.sa_data, sizeof(macOut));
    fprintf(stdout, "%s mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", ethName, macOut[0], macOut[1], macOut[2],
            macOut[3], macOut[4], macOut[5]);
    return 0;
}





int getAllMac()
{
    struct ifreq ifr;

    struct ifconf ifc;

    char buf[2048];

    int success = 0;

    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

    if (sock == -1) {

    printf("socket error\n");

    return -1;

    }

    ifc.ifc_len = sizeof(buf);

    ifc.ifc_buf = buf;

    if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {

    printf("ioctl error\n");

    return -1;

    }

    struct ifreq* it = ifc.ifc_req;

    const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));

    char szMac[64];

    int count = 0;

    for (; it != end; ++it) {

    strcpy(ifr.ifr_name, it->ifr_name);

    if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {

    if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback

    if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {

    count ++ ;

    unsigned char * ptr ;

    ptr = (unsigned char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];

    snprintf(szMac,64,"%02X:%02X:%02X:%02X:%02X:%02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));

    printf("%d,Interface name : %s , Mac address : %s \n",count,ifr.ifr_name,szMac);

    }

    }

    }else{

    printf("get mac info error\n");

    return -1;

    }
    }
}


int getdiskid_method3(char *hardc)
{
    int fd;
    struct hd_driveid hid;
    fd = open ("/dev/sda1", O_RDONLY);
    if (fd < 0)
    {
        return -1;
    }
    if (ioctl (fd, HDIO_GET_IDENTITY, &hid) < 0)
    {
        return -1;
    }
    close (fd);
    sprintf(hardc,"%s", hid.serial_no);
    return 0;
}
